from datetime import datetime
from sqlalchemy.orm import Session
from app.monitor_metrics.models.prom_network_probe import PromNetworkProbe
from app.monitor_metrics.models.prom_network_group import PromNetworkGroup
from app.monitor_metrics.models.prom_alarm_set import PromAlarmSet
from app.monitor_metrics.models.prom_alarm_group import PromAlarmGroup
from app.manage_notice.models.manage_notice_team import ManageNoticeTeam
from app.monitor_metrics.models.prom_alarm_template import PromAlarmTemplate
from app.monitor_metrics.handlers.prom_network_probe_handler import PromNetworkProbeHandler
from app.monitor_metrics.handlers.prom_alarm_template_handler import PromAlarmTemplateHandler
from app.monitor_metrics.handlers.prom_alarm_strategy_handler import PromAlarmStrategyHandler
from app.monitor_metrics.handlers.prom_alarm_set_handler import PromAlarmSetHandler
from app.monitor_metrics.handlers.prom_alarm_group_handler import PromAlarmGroupHandler
from app.monitor_metrics.utils import PromCommonUtils

from core.response import resp_400, resp_500, HTTPExceptionCustom
from core.logger import logger
from app.celery_task.models.celery_task import CeleryTask


class PromNetworkGroupHandler():
    """  network group Handler
    """
    def __init__(self):
        self.prom_network_probe_handler = PromNetworkProbeHandler()
        self.prom_alarm_template_handler = PromAlarmTemplateHandler()
        self.prom_alarm_strategy_handler = PromAlarmStrategyHandler()
        self.prom_alarm_set_handler = PromAlarmSetHandler()
        self.prom_alarm_group_handler = PromAlarmGroupHandler()


    def get_network_group_search(self, db: Session, page: int, per_page: int, field: str, value: str):
        """
        根据表字段模糊匹配，获取网络探测组信息
        """
        try:
            field_info = {field: value}
            order_info = {"department_uuid":"asc", "name":"asc"}
            result = PromNetworkGroup.filter_by_field_search(db, page, per_page, field_info, order_info)
            if not result:
                logger.error(f"get network group search, result is null, {field}:{value}")
                return False, None
        except Exception as e:
            message = f"get network group search by {field}:{value} error => {e}"
            logger.exception(message)
            return resp_500(message)

        return True, result


    def get_network_group_match(self, db: Session, page: int, per_page: int, field: str, value: str):
        """
        根据表字段完全匹配，获取网络探测组信息
        """
        try:
            result = PromNetworkGroup.filter_by_field_match(db, page, per_page, {field: value})
            if not result:
                logger.error(f"get network group match, result is null, {field}:{value}")
                return False, None
        except Exception as e:
            message = f"get network group match by {field}:{value} error => {e}"
            logger.exception(message)
            return resp_500(message)

        return True, result


    def get_network_group_probes(self, db: Session, uuid: int):
        """
        根据表字段完全匹配，获取网络探测组里面的任务信息
        """
        try:
            network_group_object = PromNetworkGroup.get_object_by_uuid(db, uuid)
            if not network_group_object:
                # 如果存在， 则异常返回
                logger.error(f"get network group probes failed, uuid:{uuid} was exist")
                return False, None

            result = PromNetworkProbe.get_object_info_by_group_uuid(db, uuid)
            # 过滤内部标签
            for probe in result:
                probe["labels"] = {
                    key: value
                    for key, value in probe["labels"].items()
                    if not key.startswith("i_")
                }
        except Exception as e:
            message = f"get network group probes uuid:{uuid} error => {e}"
            logger.exception(message)
            return resp_500(message)

        return True, result


    def get_network_group_template(self, db: Session, uuid: int):
        """
        获取网络探测组绑定的，告警模板详细信息
        """
        try:
            network_group_object = PromNetworkGroup.get_object_by_uuid(db, uuid)
            if not network_group_object:
                # 如果存在， 则异常返回
                logger.error(f"get network group template failed, uuid:{uuid} was exist")
                return False, None

            result_info = []
            for template_uuid in network_group_object.templates_uuid:
                template_info =  PromAlarmTemplate.get_object_info_by_uuid(db, template_uuid)
                result_info.append(template_info)
        except Exception as e:
            message = f"get network group:{uuid} template error => {e}"
            logger.exception(message)
            return resp_500(message)

        return True, result_info


    def get_network_group_notice(self, db: Session, uuid: int):
        """
        获取网络探测组指定的通知小组详细信息
        """
        try:
            network_group_object = PromNetworkGroup.get_object_by_uuid(db, uuid)
            if not network_group_object:
                # 如果存在， 则异常返回
                logger.error(f"get network group notice team failed, uuid:{uuid} was exist")
                return False, None

            result_info = []
            for notice_team_uuid in network_group_object.notice_teams_uuid:
                notice_team_info = ManageNoticeTeam.get_object_info_by_uuid(db, notice_team_uuid)
                result_info.append(notice_team_info)
        except Exception as e:
            message = f"get network group:{uuid} notice team error => {e}"
            logger.exception(message)
            return resp_500(message)

        return True, result_info



    def add_network_group_to_alarm_set(self, db: Session, network_group_info: dict):
        """
        增加网络探测组的规则集
        """
        alarm_set_name = PromCommonUtils.get_alarm_set_name(network_group_info)
        if PromAlarmSet.get_object_by_name(db, alarm_set_name):
            logger.warning(f"add_network_group_to_alarm_set: alarm_set_name:{alarm_set_name} was exist")
            return True

        # 创建网络探测组的规则集.
        alarm_set_data = {
            "name": alarm_set_name,
            "classes": "prometheus",
            "comment": f"network_group:{network_group_info['name']}所有的告警规则"
        }
        result = self.prom_alarm_set_handler.add_alarm_set(db, alarm_set_data)
        if not result:
            logger.error(f"add_network_group_to_alarm_set: add alarm set failed")
            return False

        return True


    def add_network_group(self, db: Session, data: dict):
        """
        创建网络探测组
        """
        try:
            network_group_object = PromNetworkGroup.get_object_by_name(db, data["name"])
            if network_group_object:
                # 如果存在， 则异常返回
                logger.error(f"add network group failed, {data['name']} was exist")
                return False

            # 创建告警规则集
            result = self.add_network_group_to_alarm_set(db, data)
            if not result:
                logger.error(f"add network group to alarm set failed")
                return False

            result = PromNetworkGroup.add(db, data)
            if not result:
                logger.error(f"add network group to database failed")
                return False
        except Exception as e:
            message = f"add network group error"
            logger.exception(f"{message} data:{data} => {e}")
            return resp_500(message)

        return True



    def update_network_group(self, db: Session, data: dict):
        """
        修改网络探测组信息
        """
        try:
            network_group_object = PromNetworkGroup.get_object_by_uuid(db, data["uuid"])
            if not network_group_object:
                # 如果不存在， 则异常返回
                logger.error(f"update network group failed, uuid:{data['uuid']} not exist")
                return False

            # 更新网络探测组的信息
            result = PromNetworkGroup.update(db, data)
            if not result:
                logger.error(f"update network group failed")
                return False
        except Exception as e:
            message = f"update group failed error"
            logger.exception(f"{message} data:{data} => {e}")
            return resp_500(message)

        return True




    def delete_network_group_to_alarm_set(self, db: Session, data: dict):
        """
        删除网络探测组的规则集
        """
        network_group_info = PromNetworkGroup.get_object_info_by_uuid(db, data["uuid"])
        alarm_set_name = PromCommonUtils.get_alarm_set_name(network_group_info)
        alarm_set_object = PromAlarmSet.get_object_by_name(db, alarm_set_name)
        if not alarm_set_object:
            logger.warning(f"delete_network_group_to_alarm_set nothing alarm_set_name:{alarm_set_name} not exist")
            return True

        # 删除的规则集.
        alarm_set_info = PromAlarmSet.get_object_info_by_name(db, alarm_set_name)
        result = self.prom_alarm_set_handler.delete_alarm_set(db, alarm_set_info)
        if not result:
            logger.error(f"delete_network_group_to_alarm_set: delete alarm set failed")
            return False

        return True


    def delete_network_group(self, db: Session, data: dict):
        """
        删除网络探测组信息
        """
        try:
            network_group_object = PromNetworkGroup.get_object_by_uuid(db, data['uuid'])
            if not network_group_object:
                # 如果不存在， 则异常返回
                logger.error(f"delete network group failed, uuid:{data['uuid']} not exist")
                return False

            # 网络探测组内还有探测任务，不能删除
            if len(network_group_object.network_probes) != 0:
                logger.error(f"delete network group failed, name:{network_group_object.name} has probes in it")
                return False


            # 网络探测组还有绑定的告警模板，不能删除
            network_group_info = PromNetworkGroup.get_object_info_by_uuid(db, data['uuid'])
            if len(network_group_info["templates_uuid"]) != 0:
                logger.error(f"delete network group failed, name:{network_group_object.name} has templates in it")
                return False

            # 从prometheus中，删除告警集合
            result = self.delete_network_group_to_alarm_set(db, data)
            if not result:
                logger.error(f"delete_network_group: delete alarm set failed")
                return False

            # 从数据库中，删除告网络探测组
            PromNetworkGroup.delete_object_by_uuid(db, data['uuid'])
        except Exception as e:
            message = f"delete network group error"
            logger.exception(f"{message} data:{data} => {e}")
            return resp_500(message)

        return True



    # ==== 更新网络探测组的负责人操作 ====
    def put_network_group_notice(self, db: Session, data: dict):
        """
        更新网络探测组的负责人
        """
        try:
            network_group_object = PromNetworkGroup.get_object_by_uuid(db, data["uuid"])
            if not network_group_object:
                # 如果不存在， 则异常返回
                logger.error(f"update network group notice failed, uuid:{data['uuid']} not exist")
                return False

            network_group_info = PromNetworkGroup.get_object_info_by_uuid(db, data["uuid"])
            notice_teams_uuid = network_group_info["notice_teams_uuid"]

            # 更新网络探测组的信息
            result = PromNetworkGroup.update(db, data)
            if not result:
                logger.error(f"put_network_group_notice to database failed")
                return False

            # 更新主机绑定的模板
            for template_uuid in network_group_info["templates_uuid"]:
                result = self.prom_alarm_template_handler.network_group_update_bind_template(db, data["uuid"], template_uuid)
                if not result:
                    # 更新失败，回滚主通知组信息
                    data["notice_teams_uuid"] = notice_teams_uuid
                    PromNetworkGroup.update(db, data)

                    # 失败返回
                    logger.error(f"put_network_group_notice update bind template:{template_uuid} failed")
                    return False
        except Exception as e:
            message = f"update network group notice failed error"
            logger.exception(f"{message} data:{data} => {e}")
            return resp_500(message)

        logger.info(f"put_network_group_notice success")
        return True



    # ==== 网络探测组的服务器添加和移除操作 ====
    def network_group_add_probes(self, db: Session, data: dict):
        """
        网络探测组批量添加已存在的探测任务
        """
        try:
            network_group_object = PromNetworkGroup.get_object_by_uuid(db, data["network_group_uuid"])
            if not network_group_object:
                # 如果不存在， 则异常返回
                logger.error(f"add network group probes failed, network_group_uuid:{data['network_group_uuid']} not exist")
                return False

            for network_probe_uuid in data["network_probes_uuid"]:
                network_probe_object = PromNetworkProbe.get_object_by_uuid(db, network_probe_uuid)
                if not network_probe_object:
                    logger.warning(f"add_network_group_probes: network_probe_uuid:{network_probe_uuid} not exist")
                    continue

                # 修改网络探测任务所属的组
                network_probe_info = PromNetworkProbe.get_object_info_by_uuid(db, network_probe_uuid)
                network_probe_info["network_group_uuid"] = data["network_group_uuid"]
                network_probe_info.pop("network_group")
                result = self.prom_network_probe_handler.update_network_probe(db, network_probe_info)
                if not result:
                    logger.error(f"network_group:{data['network_group_uuid']} add {network_probe_info['name']} failed")
                    return False
        except Exception as e:
            message = f"add_network_group_probes:{data['network_group_uuid']} error"
            logger.exception(f"{message} => {e}")
            return resp_500(message)

        return True



    # ==== 网络探测组的告警模板绑定和解绑操作 ====
    def network_group_bind_template(self, db: Session, data: dict):
        """
        网络探测组绑定模板
        """
        try:
            network_group_object = PromNetworkGroup.get_object_by_uuid(db, data["network_group_uuid"])
            if not network_group_object:
                # 如果不存在， 则异常返回
                logger.error(f"network_group bind template failed, network_group_uuid:{data['network_group_uuid']} not exist")
                return False

            alarm_template_object = PromAlarmTemplate.get_object_by_uuid(db, data["template_uuid"])
            if not alarm_template_object:
                # 如果不存在， 则异常返回
                logger.error(f"network_group bind template failed, template_uuid:{data['template_uuid']} not exist")
                return False

            # 更新数据库中的信息
            result = PromNetworkGroup.add_template(db, data["network_group_uuid"], data["template_uuid"])
            if not result:
                logger.error(f"network_group_uuid:{data['network_group_uuid']} add template_uuid:{data['template_uuid']} failed")
                return False

            # 网络探测组绑定告警模板
            result = self.prom_alarm_template_handler.network_group_bind_template(db, data["network_group_uuid"], data["template_uuid"])
            if not result:
                # 回滚数据库
                PromNetworkGroup.delete_template(db, data["network_group_uuid"], data["template_uuid"])

                logger.error(f"network_group_uuid:{data['network_group_uuid']} bind template_uuid:{data['template_uuid']} failed")
                return False

        except Exception as e:
            message = f"network_group bind template error"
            logger.exception(f"{message} data:{data} => {e}")
            return resp_500(message)

        logger.info(f"network_group_uuid:{data['network_group_uuid']} bind template_uuid:{data['template_uuid']} success")
        return True



    def network_group_unbound_template(self, db: Session, data: dict):
        """
        网络探测组解绑模板
        """
        try:
            network_group_object = PromNetworkGroup.get_object_by_uuid(db, data["network_group_uuid"])
            if not network_group_object:
                # 如果不存在， 则异常返回
                logger.error(f"network_group_unbound_template failed, network_group_uuid:{data['network_group_uuid']} not exist")
                return False

            alarm_template_object = PromAlarmTemplate.get_object_by_uuid(db, data["template_uuid"])
            if not alarm_template_object:
                # 如果不存在， 则异常返回
                logger.error(f"network_group_unbound_template failed, template_uuid:{data['template_uuid']} not exist")
                return False

            # 网络探测组解绑告警模板
            result = self.prom_alarm_template_handler.network_group_unbound_template(db, data["network_group_uuid"], data["template_uuid"])
            if not result:
                logger.error(f"network_group_uuid:{data['network_group_uuid']} unbound template_uuid:{data['template_uuid']} failed")
                return False

            # 更新数据库中网络探测组的信息
            result = PromNetworkGroup.delete_template(db, data["network_group_uuid"], data["template_uuid"])
            if not result:
                logger.error(f"network_group_uuid:{data['network_group_uuid']} delete_template template_uuid:{data['template_uuid']} failed")
                return False
        except Exception as e:
            message = f"network_group unbound template error"
            logger.exception(f"{message} data:{data} => {e}")
            return resp_500(message)

        logger.info(f"network_group_uuid:{data['network_group_uuid']} unbound template_uuid:{data['template_uuid']} success")
        return True




